-- Parsec
-- Module 'scanner'

function trim_verb(vb)
  if vb then
    if type(vb) == "function" then
      vb = vb(parser);
    end
    local idx = string.find(vb, "%s");
    if idx ~= nil and idx > 1 then
      vb = string.sub(vb, 1, idx-1);
    end
  end
  return vb;
end

function get_verb(id)
  local verbs = nvl(here().verbs,game.verbs);
  local vob = verbs[id];
  if vob then
    local vb = trim_verb(vob[1]);
    return vb;
  end
end

function verb_with(s, pf, cnd, coll, with, withAux)
  local ret = "";
  local vb = get_verb(s.verbnr);
  local ovb = vb;
  local aux = nil;
  local aux2 = nil;
  if with then
    vb = "with" .. vb;
    aux = true;
  elseif withAux then
    vb = "aux" .. vb;
    aux2 = true;
  end
  local map = articles[ovb];
  local p = pf;
  for i,v in ipairs(coll()) do
    v.aux = aux;
    v.aux2 = aux2;
    if type(pf) == "function" then
      p = pf(s);
    else
      p = pf;
    end
    if map ~= nil then
      local va = nil;
      if v.articles ~= nil then
        va = v.articles[ovb];
      end
      if va ~= nil and map[va] ~= nil then
        p = map[va];
      end
    end
    for k,ov in pairs(v) do
      --print("_with:"..deref(v)..";k="..k..";vb="..vb);
      if k == vb 
        and (not with or ov)
        and (not withAux or ov)
        and (cnd == nil or cnd(v)) 
        and not v.hidden then
        ret = ret .. "{" .. deref(v) .. "}" .. p .. "|";
      end
    end
  end
  return ret;
end

function verb_with_obj_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, objs);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function verb_with_inv_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, inv);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function verb_with_obj_inv_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, objs);
    local ret = ret .. verb_with(s, p, cnd, inv);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function aux_with_obj_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, objs, true);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function aux_with_inv_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, inv, true);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function aux_with_obj_inv_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, objs, true);
    local ret = ret .. verb_with(s, p, cnd, inv, true);
    if app ~= nil then
      return app .. "|" .. ret;
    else
      return ret;
    end
  end
end

function aux2_with_obj_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, objs, false, true);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function aux2_with_inv_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, inv, false, true);
    if app ~= nil and rcall(app,s) ~= nil then
      return rcall(app,s) .. "|" .. ret;
    else
      return ret;
    end
  end
end

function aux2_with_obj_inv_(p, cnd, app)
  return function(s)
    local ret = verb_with(s, p, cnd, objs, false, true);
    local ret = ret .. verb_with(s, p, cnd, inv, false, true);
    if app ~= nil then
      return app .. "|" .. ret;
    else
      return ret;
    end
  end
end
